<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Handling POSTs</title>
</head>

<body>
<h1>Handling POSTs</h1>

<p>All of the previous examples have focused on <code>GET</code>
requests. Unlike <code>GET</code> requests, <code>POST</code> requests can have
a request body - extra data after the request headers; for example, data
representing the contents of an HTML form. Twisted Web makes this data available
to applications via the <code class="API"
base="twisted.web.server">Request</code> object.</p>

<p>Here's an example web server which renders a static HTML form and then
generates a dynamic page when that form is posted back to it. Disclaimer: While
it's convenient for this example, it's often not a good idea to make a resource
that <code>POST</code>s to itself; this isn't about Twisted Web, but the nature
of HTTP in general; if you do this in a real application, make sure you
understand the possible negative consequences.</p>

<p>As usual, we start with some imports. In addition to the Twisted imports,
this example uses the <code>cgi</code> module to <a
href="http://en.wikipedia.org/wiki/Cross-site_scripting">escape user-entered
content</a> for inclusion in the output.</p>

<pre class="python">
from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import reactor

import cgi
</pre>

<p>Next, we'll define a resource which is going to do two things. First, it will
respond to <code>GET</code> requests with a static HTML form:</p>

<pre class="python">
class FormPage(Resource):
    def render_GET(self, request):
        return '&lt;html&gt;&lt;body&gt;&lt;form method="POST"&gt;&lt;input name="the-field" type="text" /&gt;&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;'
</pre>

<p>This is similar to the resource used in a <a
href="dynamic-content.xhtml">previous installment</a>. However, we'll now add
one more method to give it a second behavior; this <code>render_POST</code>
method will allow it to accept <code>POST</code> requests:</p>

<pre class="python">
...
    def render_POST(self, request):
        return '&lt;html&gt;&lt;body&gt;You submitted: %s&lt;/body&gt;&lt;/html&gt;' % (cgi.escape(request.args["the-field"][0]),)
</pre>

<p>The main thing to note here is the use
of <code>request.args</code>. This is a dictionary-like object that
provides access to the contents of the form. The keys in this
dictionary are the names of inputs in the form. Each value is a list
containing strings (since there can be multiple inputs with the same
name), which is why we had to extract the first element to pass
to <code>cgi.escape</code>. <code>request.args</code> will be
populated from form contents whenever a <code>POST</code> request is
made with a content type
of <code>application/x-www-form-urlencoded</code>
or <code>multipart/form-data</code> (it's also populated by query
arguments for any type of request).</p>

<p>Finally, the example just needs the usual site creation and port setup:</p>

<pre class="python">
root = Resource()
root.putChild("form", FormPage())
factory = Site(root)
reactor.listenTCP(8880, factory)
reactor.run()
</pre>

<p>Run the server and
visit <a href="http://localhost:8880/form">http://localhost:8880/form</a>,
submit the form, and watch it generate a page including the value you entered
into the single field.</p>

<p>Here's the complete source for the example:</p>

<pre class="python">
from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import reactor

import cgi

class FormPage(Resource):
    def render_GET(self, request):
        return '&lt;html&gt;&lt;body&gt;&lt;form method="POST"&gt;&lt;input name="the-field" type="text" /&gt;&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;'

    def render_POST(self, request):
        return '&lt;html&gt;&lt;body&gt;You submitted: %s&lt;/body&gt;&lt;/html&gt;' % (cgi.escape(request.args["the-field"][0]),)

root = Resource()
root.putChild("form", FormPage())
factory = Site(root)
reactor.listenTCP(8880, factory)
reactor.run()
</pre>

</body>
</html>
